package org.xutils.db.table;

import android.database.Cursor;
import android.text.TextUtils;

import org.xutils.db.annotation.Column;
import org.xutils.db.converter.ColumnConverter;
import org.xutils.db.converter.ColumnConverterFactory;
import org.xutils.db.sqlite.ColumnDbType;
import org.xutils.db.xDb;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @Date: 2021/5/25 18:11
 * @Email: zzh_hz@126.com
 * @QQ: 1299234582
 * @Author: zzh
 * @Description: 列属性
 */
public final class ColumnEntity {
    private static final String TAG = "-H-ColumnEntity";

    protected final String name;
    private final String property;
    private final boolean isId;
    private final boolean isAutoId;
    /**
     * 数值类型主键是否自动生成
     */
    protected final boolean isAutoNumberId;
    /**
     * 随机字符串类型主键是否自动生成
     */
    protected final boolean isAutoGenId;

    protected final Method getMethod;
    protected final Method setMethod;

    protected final Field columnField;
    protected final ColumnConverter columnConverter;

    /**
     * @param entityType 表模型
     * @param field      字段名称
     * @param column     列名称
     */
    /* package */ ColumnEntity(Class<?> entityType, Field field, Column column) {
        field.setAccessible(true);

        this.columnField = field;
        this.name = column.name();
        this.property = column.property();
        this.isId = column.isId();


        Class<?> fieldType = field.getType();
        this.isAutoId = this.isId && column.autoGen() && ColumnUtils.isAutoIdType(fieldType);
        this.isAutoNumberId = this.isAutoId && isNumberPK(fieldType);
        this.isAutoGenId = this.isAutoId && (!isNumberPK(fieldType));

        this.columnConverter = ColumnConverterFactory.getColumnConverter(fieldType);


        this.getMethod = ColumnUtils.findGetMethod(entityType, field);
        if (this.getMethod != null && !this.getMethod.isAccessible()) {
            this.getMethod.setAccessible(true);
        }
        this.setMethod = ColumnUtils.findSetMethod(entityType, field);
        if (this.setMethod != null && !this.setMethod.isAccessible()) {
            this.setMethod.setAccessible(true);
        }
    }

    public boolean isAutoNumberId() {
        return isAutoNumberId;
    }


    public boolean isAutoGenId() {
        return isAutoGenId;
    }

    /**
     * 主键类型是int,Integer,long,Long类型。主键只能是字符串类型或者数值类型
     */
    public boolean isNumberPK(Class<?> fieldType) {
        return !String.class.equals(fieldType);
    }

    public void setValueFromCursor(Object entity, Cursor cursor, int index) {
        Object value = columnConverter.getFieldValue(cursor, index);
        if (value == null) return;

        if (setMethod != null) {
            try {
                setMethod.invoke(entity, value);
            } catch (Throwable e) {
                if (xDb.getInstance().isDebug()) {
                    android.util.Log.d(TAG, "--db-: 更新操作，ID 不为空：" + value + "，构建更新SQL");
                }
            }
        } else {
            try {
                this.columnField.set(entity, value);
            } catch (Throwable e) {
                if (xDb.getInstance().isDebug()) {
                    android.util.Log.d(TAG, e.toString());
                }
            }
        }
    }

    @SuppressWarnings("unchecked")
    public Object getColumnValue(Object entity) {
        Object fieldValue = getFieldValue(entity);
        if (this.isAutoId && (fieldValue == null || fieldValue.equals(0L) || fieldValue.equals(0) || TextUtils.equals("", fieldValue.toString()))) {
            return null;
        }
        return columnConverter.fieldValue2DbValue(fieldValue);
    }

    public void setAutoIdValue(Object entity, String value) {
        Object idValue = value;

        if (setMethod != null) {
            try {
                setMethod.invoke(entity, idValue);
            } catch (Throwable e) {
                if (xDb.getInstance().isDebug()) {
                    android.util.Log.d(TAG, e.toString());
                }
            }
        } else {
            try {
                this.columnField.set(entity, idValue);
            } catch (Throwable e) {
                if (xDb.getInstance().isDebug()) {
                    android.util.Log.d(TAG, e.toString());
                }
            }
        }
    }

    public void setAutoIdValue(Object entity, long value) {
        Object idValue = value;
        if (ColumnUtils.isInteger(columnField.getType())) {
            idValue = (int) value;
        }

        if (setMethod != null) {
            try {
                setMethod.invoke(entity, idValue);
            } catch (Throwable e) {
                if (xDb.getInstance().isDebug()) {
                    android.util.Log.d(TAG, e.toString());
                }
            }
        } else {
            try {
                this.columnField.set(entity, idValue);
            } catch (Throwable e) {
                if (xDb.getInstance().isDebug()) {
                    android.util.Log.d(TAG, e.toString());
                }
            }
        }
    }

    public Object getFieldValue(Object entity) {
        Object fieldValue = null;
        if (entity != null) {
            if (getMethod != null) {
                try {
                    fieldValue = getMethod.invoke(entity);
                } catch (Throwable e) {
                    if (xDb.getInstance().isDebug()) {
                        android.util.Log.d(TAG, e.toString());
                    }
                }
            } else {
                try {
                    fieldValue = this.columnField.get(entity);
                } catch (Throwable e) {
                    if (xDb.getInstance().isDebug()) {
                        android.util.Log.d(TAG, e.toString());
                    }
                }
            }
        }
        return fieldValue;
    }

    public String getName() {
        return name;
    }

    public String getProperty() {
        return property;
    }

    public boolean isId() {
        return isId;
    }

    public boolean isAutoId() {
        return isAutoId;
    }

    public Field getColumnField() {
        return columnField;
    }

    public ColumnConverter getColumnConverter() {
        return columnConverter;
    }

    public ColumnDbType getColumnDbType() {
        return columnConverter.getColumnDbType();
    }

    @Override
    public String toString() {
        return name;
    }
}
